const wechat = require('co-wechat');
const path = require('path');

module.exports = app => {

    if (!app.config.weixin.token) {
        throw new Error('config.weixin.token is required, provide it via config file or env WEIXIN_MESSAGE_TOKEN');
    }

    const debug = app.config.debug;
    const appid = app.config.weixin.appId;

    return class WeixinController extends app.Controller {

        constructor(...args) {
            super(...args);
            this._callback = wechat({
                appid: app.config.weixin.appId,
                token: app.config.weixin.token,
                encodingAESKey: app.config.weixin.encodingAESKey
            }).middleware((message, ctx) => this.middleware(message, ctx));
        }

        callback(ctx, next) {
            console.log('###########################',ctx)
            return this._callback(ctx, next);
        }

        async verify(ctx, next) {
            if (!app.config.weixin.verifyFile) {
                ctx.throw(404);
            }
            ctx.body = app.config.weixin.verifyFile;
        }

        async middleware(message, ctx) {
            const openid = message.FromUserName;
            await ctx.api.bind.getWeixinUserInfo(openid);
            if (message.MsgType.toLowerCase() === 'event') {
                switch (message.Event.toLowerCase()) {
                    case 'unsubscribe':
                        return await this.unsubscribe(message, ctx);
                    case 'subscribe':
                        return await this.subscribe(message, ctx);
                    case 'scan':
                        if (message.Ticket) {
                            return await this.subscribe(message, ctx);
                        }
                        break;
                    case 'click':
                        switch (message.EventKey.toLowerCase()) {
                            case 'order_drugs':
                                return await this.orderDrugs(message, ctx);
                            case 'contact_us':
                                return await this.contactUs(message, ctx);
                            case 'coming_gift':
                                return await this.comingGift(message, ctx);
                        }
                        break;
                }
            }
            if (message.MsgType.toLowerCase() === 'text') {
                const str = message.Content && message.Content.toString().toLowerCase() || '';
                if (debug && str === 'debug:removebind') {
                    return await this.debugDelBind(message, ctx);
                }
                if (debug && str === 'debug:bindurl') {
                    return await this.debugBindUrl(message, ctx);
                }
                if (debug && str === 'debug:orderurl') {
                    return await this.debugOrderUrl(message, ctx);
                }
                if (debug && str === 'debug:tags') {
                    return await this.debugListMyTags(message, ctx);
                }
            }
            //发送消息给MA
            if (message.MsgType.toLowerCase() === 'text' ||
                message.MsgType.toLowerCase() === 'voice' ||
                message.MsgType.toLowerCase() === 'image') {
                const openid = message.FromUserName;
                const patientId = await ctx.api.bind.getBindPatientByWeixin(openid);
                await ctx.api.bind.sendMessageToMA(app.config.weixin.appId, openid, { ...message, patientId });
            }
            return '';
        }

        //取消订阅后，修改状态。
        async unsubscribe(message, ctx) {
            app.logger.warn('[unsubscribe]', message);
            const openid = message.FromUserName;
            const user = await ctx.api.bind.getWeixinUserInfo(openid);
            app.logger.warn('[user]', user);
            if (user) {
                user.subscribe = false;
                user.subscribe_time = null;
                await ctx.api.bind.setWeixinUserInfo(openid, user);
            }
            return '';
        }
        //公共号欢迎语--通过公共号label获取欢迎语配置
        async subscribe(message, ctx) {
            app.logger.warn('[subscribe]', message);
            const openid = message.FromUserName;
            const patientId = await ctx.api.bind.getBindPatientByWeixin(openid);
            let configType = 4;
            if (!patientId) {
                if (message.Ticket) {
                    //如果是未关注，EventKey会带qrscene_做为前缀。
                    const { userType, sceneId, channel } = JSON.parse(message.EventKey.replace('qrscene_', ''));
                    //发送绑定消息给MA
                    if (userType == 3) {
                        try {
                            await ctx.api.bind.sendBindMessageToMA(appid, openid, message.EventKey);
                        } catch (e) {
                            app.logger.error('weixin bind sendBindMessageToMA <-', e);
                        }
                    }
                    //保存患者推荐吗
                    if (userType == 1) {
                        const user = await ctx.api.bind.getWeixinUserInfo(openid);
                        if (user) {
                            await ctx.api.bind.setWeixinUserInfo(openid, { recommendBusinessCode });
                        }
                    }
                    if (channel) {
                        const user = await ctx.api.bind.getWeixinUserInfo(openid);
                        if (user) {
                            await ctx.api.bind.setWeixinUserInfo(openid, { channel });
                        }
                    }
                }
                configType = 3;
            }
            return await this.contactUs(message, ctx, configType);
        }

        // 客服预订
        async orderDrugs(message, ctx) {
            const openid = message.FromUserName;
            const asset = 'kefu.png';
            const text = '点击键盘，输入您要预订的药品，客服会尽快与您联系';
            app.runInBackground(async () => {
                const filename = path.resolve(__dirname, '..', '..', 'assets', asset);
                const mediaId = await this.getImageMediaId(`assets/${asset}`, filename);
                app.logger.info('weixin api sendImage ->', openid, mediaId);
                const r = await app.weixinApi.sendImage(openid, mediaId);
                app.logger.info('weixin api sendImage <-', r);
                const r_text = await app.weixinApi.sendText(openid, text);
                app.logger.info('weixin api sendText <-', r_text);
            });
            return '';
        }

        // 联系客服 --通过公共号label获取欢迎语配置
        async contactUs(message, ctx, configType) {
            const openid = message.FromUserName;
            const wx = await ctx.api.bind.getWeixinInfo(app.config.weixin.appId);
            const patientId = await ctx.api.bind.getBindPatientByWeixin(openid);
            const contentList = await ctx.api.portal.getConfigurations(wx.label, undefined, patientId);
            const contentObj = contentList ? contentList.find(config => config.configType == (configType || 4)) : null;
            // const media = contentList ? contentList.find(config => config.configType == 5) : null;
            // const asset = 'kefu.png';
            app.runInBackground(async () => {
                // if (media && contentObj) {
                //     const filename = path.resolve(__dirname, '..', '..', 'assets', asset);
                //     const mediaId = await this.getImageMediaId(`assets/${asset}`, filename);
                //     app.logger.info('weixin api sendImage ->', openid, mediaId);
                //     const r = await app.weixinApi.sendImage(openid, mediaId);
                //     app.logger.info('weixin api sendImage <-', r);
                // }
                if (contentObj) {
                    app.logger.info('weixin api sendText <-', contentObj.content);
                    const r_text = await app.weixinApi.sendText(openid, contentObj.content);
                    app.logger.info('weixin api sendText <-', r_text);
                }

            });
            return '';
        }

        // 拉新有礼
        async comingGift(message, ctx) {
            const openid = message.FromUserName;
            const text = `敬请期待`;
            app.runInBackground(async () => {
                const r_text = await app.weixinApi.sendText(openid, text);
                app.logger.info('weixin api sendText <-', r_text);
            });
            return '';
        }

        // 调用 weixin api 发送文字
        async sendAssetText(openid, text) {
            app.runInBackground(async () => {
                const r = await app.weixinApi.sendText(openid, text);
                app.logger.info('weixin api sendText <-', r);
            });
        }

        // 调用 weixin api 发送图片
        async sendAssetImage(openid, asset) {
            app.runInBackground(async () => {
                const filename = path.resolve(__dirname, '..', '..', 'assets', asset);
                const mediaId = await this.getImageMediaId(`assets/${asset}`, filename);
                app.logger.info('weixin api sendImage ->', openid, mediaId);
                const r = await app.weixinApi.sendImage(openid, mediaId);
                app.logger.info('weixin api sendImage <-', r);
            });
        }

        async getImageMediaId(fileId, filePath) {
            let r = await app.api.clients.get('bind').getToken(`media/${appid}/${fileId}`);
            if (r && Date.now() > r.expiredAt) {
                r = null; //expire
            }
            if (!r) {
                r = {
                    expiredAt: Date.now() + 48 * 3600 * 1000 //expired at 2 days
                };
                app.logger.info('weixin api uploadMedia ->', filePath, 'image');
                let media = await app.weixinApi.uploadMedia(filePath, 'image');
                if (typeof media === 'string' || media instanceof Buffer) {
                    media = JSON.parse(media);
                }
                app.logger.info('weixin api uploadMedia <-', media);
                if (!media.media_id) {
                    throw new Error('uploadMedia failed, no media_id in response');
                }
                r.mediaId = media.media_id;
                await app.api.clients.get('bind').setToken(`media/${fileId}`, r);
            }
            return r.mediaId;
        }

        async debugDelBind(message, ctx) {
            const openid = message.FromUserName;
            const patientId = await ctx.api.bind.getBindPatientByWeixin(openid);
            if (!patientId) {
                return {
                    content: `未找到绑定患者`,
                    type: 'text',
                }
            }
            await ctx.api.bind.delBindPatient(openid);
            return {
                content: `绑定已删除`,
                type: 'text',
            }
        }

        async debugBindUrl(message, ctx) {
            const openid = message.FromUserName;
            return {
                content: `${app.config.crm.webUrl}/weixin/bind?openid=${openid}&appid=${app.config.weixin.appId}`,
                type: 'text'
            }
        }

        async debugOrderUrl(message, ctx) {
            const openid = message.FromUserName;
            return {
                content: `${app.config.crm.webUrl}/?modal=createOrder&modalParam=${patientId}&channel=12`,
                type: 'text'
            }
        }

        async debugListMyTags(message, ctx) {
            const openid = message.FromUserName;
            const tags = await ctx.api.bind.callWeixinApi("getTags");
            const tagIdList = await ctx.api.bind.callWeixinApi("getIdList", openid);
            const tagsMessage = tagIdList.tagid_list.map(id => {
                const tag = tags.tags.find(t => t.id === id);
                if (!tag) return;
                return `[${tag.id}] ${tag.name}`
            }).filter(a => a).join("，");
            return {
                content: `您的标签有：${tagsMessage}。`,
                type: 'text'
            };
        }

        async initMenu(ctx) {
            let webUrl = app.config.weixin.webUrl;
            const wx = await ctx.api.bind.getWeixinInfo(app.config.weixin.appId);
            if (webUrl[webUrl.length - 1] === '/') {
                webUrl = webUrl.substr(0, webUrl.length - 1);
            }
            // 企业会员专区地址
            let enterpriseUrl = null
            if(webUrl.indexOf('demo-wuhuwx')>-1){
                // demo
                enterpriseUrl = 'https://demo-boc-h5.wanhuhealth.com/login1?channelCode=10300570'
            }else if(webUrl.indexOf('test-wanhuwx')>-1){
                // 测试
                enterpriseUrl = 'https://10.1.10.25:41190/login1?channelCode=10300006'
            }else{
                // 正式
                enterpriseUrl = 'https://boc-h5.wanhuhealth.com/login1?channelCode=10300677'
            }
            const menu = {
                "button": [
                    {
                        "name": "会员专区",
                        "sub_button": [
                            {
                                "name": "会员服务",
                                "type": "view",
                                "url": `${webUrl}/newHealthHomePage`,
                            },
                            {
                                "name": "会员商城",
                                "type": "view",
                                "url": `${webUrl}/toBaiji`
                            },
                            // {
                            //     "name": "企业会员专区",
                            //     "type": "view",
                            //     "url": `${enterpriseUrl}`
                            // },
                        ]
                    },
                    {
                        "type": "view",
                        "name": "视频医生",
                        "url": `${webUrl}/DoctorGo`
                    },
                    {
                        "name": "关于我们",
                        "type": "view",
                        "url": `http://www.wanhuhealth.com`
                    }
                ]
            };
            ctx.logger.info("set weixin menu", JSON.stringify(menu));
            const r = await app.weixinApi.createMenu(menu);
            ctx.logger.info("result of set weixin menu", r);
            ctx.body = wx;
        }

        async initUnionId(ctx) {
            await ctx.api.bind.initUnionId()
            ctx.body = {
                code: 0,
            }
        }
    }
}
